package de.fhin.mas.util;

/**
 * <p>
 * A class that provides static methods to check method arguments, e.g. check if
 * an argument is not <tt>null</tt> or is an instance of a specific class.
 * <p>
 * All methods have an "optional" context parameter. If the check fails, the
 * context's is put into the exception that is thrown. This way you can provide
 * some information in which context the check has failed and avoid to create a
 * <tt>String</tt> object in the default case, when the check passes
 * successfully.
 * 
 * @author Alexander Weickmann
 */
public final class ArgumentCheck {

	/**
	 * Checks if the indicated argument is <tt>null</tt>. If so a
	 * <tt>NullPointerException</tt> is thrown.
	 * 
	 * @param arg
	 *            The argument to check.
	 * 
	 * @throws NullPointerException
	 *             If <tt>arg</tt> is <tt>null</tt>.
	 */
	public final static void notNull(Object arg) {
		if (arg == null) {
			throw new NullPointerException();
		}
	}

	/**
	 * Checks if the indicated argument is <tt>null</tt>. If so a
	 * <tt>NullPointerException</tt> with the provided context is thrown.
	 * 
	 * @param arg
	 *            The argument to check.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws NullPointerException
	 *             If <tt>arg</tt> or <tt>context</tt> is <tt>null</tt>.
	 */
	public final static void notNull(Object arg, String context) {
		notNull(context);
		if (arg == null) {
			throw new NullPointerException(context);
		}
	}

	/**
	 * Checks if the provided array or one of the objects at the array's
	 * positions is <tt>null</tt>. If so a <tt>NullPointerException</tt> is
	 * thrown.
	 * 
	 * @param array
	 *            The array to check.
	 * 
	 * @throws NullPointerException
	 *             If any element of the provided <tt>array</tt> or the
	 *             <tt>array</tt> itself is <tt>null</tt>.
	 */
	public final static void notNull(Object[] array) {
		notNull((Object) array);
		for (int i = 0; i < array.length; i++) {
			notNull(array[i]);
		}
	}

	/**
	 * Checks if the provided array or the objects at the array positions are
	 * <tt>null</tt>. If so a <tt>NullPointerException</tt> with the provided
	 * context is thrown.
	 * 
	 * @param array
	 *            The array to check.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws NullPointerException
	 *             If any element of the provided <tt>array</tt>, the
	 *             <tt>array</tt> itself or <tt>context</tt> is <tt>null</tt>.
	 */
	public final static void notNull(Object[] array, String context) {
		notNull((Object) array);
		notNull(context);
		for (int i = 0; i < array.length; i++) {
			notNull(array[i], context);
		}
	}

	/**
	 * Checks if the indicated expression is <tt>true</tt>. If not an
	 * <tt>IllegalArgumentException</tt> is thrown.
	 * 
	 * @param expr
	 *            The expression to check.
	 * 
	 * @throws IllegalArgumentException
	 *             If the indicated expression is <tt>false</tt>.
	 */
	public final static void isTrue(boolean expr) {
		if (!expr) {
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Checks if the indicated expression is <tt>true</tt>. If not an
	 * <tt>IllegalArgumentException</tt> with the provided context is thrown.
	 * 
	 * @param expr
	 *            The expression to check.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws IllegalArgumentException
	 *             If the indicated expression is <tt>false</tt>.
	 * @throws NullPointerException
	 *             If <tt>context</tt> is <tt>null</tt>.
	 */
	public final static void isTrue(boolean expr, String context) {
		notNull(context);
		if (!expr) {
			throw new IllegalArgumentException(context);
		}
	}

	/**
	 * Checks if the indicated arguments are equal. If not an
	 * <tt>IllegalArgumentException</tt> is thrown.
	 * 
	 * @param arg1
	 *            The first argument.
	 * @param arg2
	 *            The second argument.
	 * 
	 * @throws IllegalArgumentException
	 *             If <code>arg1.equals(arg2)</code> returns <tt>false</tt>.
	 * @throws NullPointerException
	 *             If <tt>arg1</tt> or <tt>arg2</tt> is <tt>null</tt>.
	 */
	public final static void equals(Object arg1, Object arg2) {
		notNull(new Object[] { arg1, arg2 });
		if (arg1.equals(arg2)) {
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Checks if the indicated arguments are equal. If not an
	 * <tt>IllegalArgumentException</tt> with the provided context is thrown.
	 * 
	 * @param arg1
	 *            The first argument.
	 * @param arg2
	 *            The second argument.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws IllegalArgumentException
	 *             If <code>arg1.equals(arg2)</code> returns <tt>false</tt>.
	 * @throws NullPointerException
	 *             If <tt>arg1</tt>, <tt>arg2</tt> or <tt>context</tt> is
	 *             <tt>null</tt>.
	 */
	public final static void equals(Object arg1, Object arg2, String context) {
		notNull(new Object[] { arg1, arg2, context });
		if (arg1.equals(arg2)) {
			throw new IllegalArgumentException(context);
		}
	}

	/**
	 * Checks if the indicated argument is an instance of the indicated class.
	 * If not an <tt>IllegalArgumentException</tt> is thrown.
	 * 
	 * @param arg
	 *            The argument to check.
	 * @param clazz
	 *            The class arg must be an instance of.
	 * 
	 * @throws IllegalArgumentException
	 *             If <tt>arg</tt> is not an instance of <tt>clazz</tt>.
	 * @throws NullPointerException
	 *             If <tt>arg</tt> or <tt>clazz</tt> is <tt>null</tt>.
	 */
	public final static void isInstanceOf(Object arg, Class<?> clazz) {
		notNull(new Object[] { arg, clazz });
		if (!clazz.isAssignableFrom(arg.getClass())) {
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Checks if the indicated argument is an instance of the indicated class.
	 * If not an <tt>IllegalArgumentException</tt> with the provided context is
	 * thrown.
	 * 
	 * @param arg
	 *            The argument to check.
	 * @param clazz
	 *            The class arg must be an instance of.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws IllegalArgumentException
	 *             If <tt>arg</tt> is not an instance of <tt>clazz</tt>.
	 * @throws NullPointerException
	 *             If <tt>arg</tt>, <tt>clazz</tt> or <tt>context</tt> is
	 *             <tt>null</tt>.
	 */
	public final static void isInstanceOf(Object arg, Class<?> clazz,
			String context) {

		notNull(new Object[] { arg, clazz, context });
		if (!clazz.isAssignableFrom(arg.getClass())) {
			throw new IllegalArgumentException(context);
		}
	}

	/**
	 * Checks if the indicated array has the indicated length. If not an
	 * <tt>IllegalArgumentException</tt> is thrown.
	 * 
	 * @param array
	 *            The array to check.
	 * @param length
	 *            The expected array length.
	 * 
	 * @throws IllegalArgumentException
	 *             If the <tt>array</tt> has not the expected <tt>length</tt>.
	 * @throws NullPointerException
	 *             If <tt>array</tt> is <tt>null</tt>.
	 */
	public final static void length(Object[] array, int length) {
		notNull((Object) array);
		if (array.length != length) {
			throw new IllegalArgumentException();
		}
	}

	/**
	 * Checks if the indicated array has the indicated length. If not an
	 * <tt>IllegalArgumentException</tt> with the provided context is thrown.
	 * 
	 * @param array
	 *            The array to check.
	 * @param length
	 *            The expected array length.
	 * @param context
	 *            Information to provide if the test fails.
	 * 
	 * @throws IllegalArgumentException
	 *             If the <tt>array</tt> has not the expected <tt>length</tt>.
	 * @throws NullPointerException
	 *             If <tt>array</tt> or <tt>context</tt> is <tt>null</tt>.
	 */
	public final static void length(Object[] array, int length, String context) {
		notNull(new Object[] { array, context });
		if (array.length != length) {
			throw new IllegalArgumentException(context);
		}
	}

	/**
	 * Prohibit instantiation.
	 */
	private ArgumentCheck() {

	}

}
